perm filename SM[HHA,LCS] blob
sn#433844 filedate 1979-04-19 generic text, type T, neo UTF8
[DGL,BIL] TBLOOK,STRTTAB
Internal integer procedure TBLOOK(integer outloc,inloc;
integer length,scal;
reference integer dly,dlyAdr;
boolean getMem(false), round(false), TurnOn(false));
TBLOOK - table lookup, with or without rounded index.
Must release the delay unit and the memory separately.
The memory must be released with a DMREL(dlyadr).
If getMem=true then call GetDm to claim delay memory, else use values
passed to proc. If round=true then invoke round_table_lookup else
just table_lookup. Rounding acts to adjust the index into delay memory
read from the a_in port upwards if the last bit shifted out in the scale
operation was a 1. The scal term is used to determine how many places to
the right to shift the a_in value. This operation is used to bring the
a_in value into the range where it can act as an index into the table.
The scaling process in the box brings in zeros as it right-shifts.
;
[BIL]
∂ turn on table look up only at last minute;
Internal Recursive Procedure StrtTab(Integer StartTime,ModNumber);
Timing is important in use of TBLOOK, so I added the extra argument to TBLOOK,
and have put in a little procedure to turn on TBLOOK only when the user wants it.
[DGL] RAMP,RAMPER
Internal integer procedure RAMP(real inc, phase;integer outLoc);
RAMP - simple ramp generator;
! Use this routine to generate an honest ramp (without the glitch
that Sawtooth waveforms give you. Sawtooth waveform
mode in generators produce a value of 0 when the angle
term = -1 ('1000...0). An example of what to set Inc to:
if you want a ramp that goes through 15 bits, set Inc to
inc←(1/'1777777)*2↑(20-15). The ramp will be left adjusted in
sum memory. To use as an index into delay memory, set the
scale bits in the delay line to shift right by 20-15 (in our
example) = 5 bits;
! user is responsible for returning the modifier claimed;
RAMPER - generates a ramp suitable for indexing tables, with function control;
Internal integer procedure RAMPER(integer beg, dur,spacing;real phase;
record_pointer(seg) r; real funScl,funOff;
reference itemvar LsItm;
integer outLoc);
! Note, this ramp function is generated by a modifier in uniform_noise
mode in degenerate form as follows: (This example will generate a ramp
that increments by one each pass and will wrap around at 2↑20.)
M0: 00000000000000000001[0000000000]
* integer mult. low bits significant
L1: 00000000000000000000←←←
+ ↑
L0: 00000000000000000001 ↑
↓ ↑
S: 00000000000000000001→→↑ delta
The increment is a function of the value in L0. To make the
period smaller, increase L0. Note that this will make the period smaller,
and the value will be left adjusted in the 20 bit sum memory. For
instance, if L0=2↑5, then the period of the ramp function will be
2↑20-5 = 2↑15, where the period is expressed only in bits 5→20.
This left adjusted value must be shifted right 5 places to form a valid
index for a table lookup, and Pete has obligingly put a right-shift
operation in the table lookup mode of the delay units.
In the above example, the delay unit's scale term
would be set to 5 to RSH the function the appropriate number of places to
put the LSB in the rightmost bit position of the word.
This would mean that 2↑5 would be the units place in L0 and would cause
the ramp function to increment by one each pass. The values to the
right of the ones place act like fractions, e.g. 2↑4 corresponds to
the fraction .5, etc. If the value is
.5 the function will increment every two passes, etc.
The multiplier coefficient M0 is set to 1 so it has no effect.
The initial value of L1 can be used to set the phase of the ramp, i.e.
given a waveform expressed in 2↑15 bits in our example above, setting
L1 to 2↑15/2 → 2↑14 will set the phase to 180 degrees (2↑15 here can be
thought of as 2π radians).
If you wonder why not use a generator in saw wave mode to do this,
read the Specification: the killer is that in step (9) in generator processing,
in saw wave mode, when the angle term is -1 (1000000000000), then 0 is
taken! You figure out what will happen. It is also possible to use
the envelope side to make a ramp, but then the range is maximum of 2↑12.
-DGL
; ! end of comment;
[DGL] INTERP
INTERP - interpolation for delay memory;
[DGL - Feb. 19, 1979, please note, this interpolator has been found
to be not very useful for doing z-delay resampling kinds of things, since
it uses a single sum memory word length for both the index into delay
memory as well as the fraction for the interpolation. I have a method
for double precision which I may implement some day. Until then, this
is the best we have, but it would be best restricted to interpolating
table lookup.]
! Note, user is responsible for returning sum memory locations
tmp,frac, and modifiers mod0→4;
Internal procedure INTERP(integer Xz,Xn,Xnp1,indx,fracWidth;
reference integer tmp,frac,mod0,mod1,mod2,mod3,mod4);
! Abstract: This routine takes two adjacent delay memory
data from sum memory and does a linear interpolation on them. It
needs the first address used to fetch these data in order to extract
the fraction part of the address. With this fraction, it then
does the interpolation.
This takes as input four sum memory locations.
The first two: ADR and ADRP1, contain
the indexes used to retrieve the two data from delay memory.
The two data, Xn and Xn+1, are presumed to be deposited in
sum memory at XN and XNP1. The routine writes the interpolated
sample Xz into sum memory location XZ.
The way it works:
Say we are generating ramps with RAMPER and then use the
scaler term in the delay unit in TBLOOK to shift it right 5 to generate the
index to dm. That means that the low 5 bits of RAMPER's output can
be considered a fraction. Call it m, call its width w.
The formula for interpolation is then
delta*X[n + 1] + (1 - delta)*X[n]
where delta is the fractional part of the index used to retrieve Xn.
This allows us to get:
(m/w)*X[n+1] + X[n] - (m/w)*X[n]
or in our example:
m*X[n+1]/2↑5 + X[n] - m*X[n]/2↑5.
To get this result requires two steps, 1) extract the fraction
from XN, 2) apply that to the interpolation formula.
To get the fraction I use the technique of "fixing" XN, that
is, wiping out its fractional part by multiplying it by a value that
shifts it right by w bits. In the same multiply I invert the sign.
This takes one modifier. I then renormalize it and
subtract this from XN, which leaves only the fraction part of XN.
The only problem with this is that the
second modifier must reference XN as well as the result of what the
first modifier does. This requires that the second modifier acts on
the same pass as the first so that XN will still be valid.
This means that the second modifier must be at least 2*(modifier 1) + 7
ticks further down the pass.
This takes two modifiers acting in series as follows:
The first modifier is in MIXING mode,the second is in INT_MIXING.
This example is in terms of the index into delay memory being 15 bits
left adjusted in sum memory, and therefore the right 5 bits are the
fraction. RAMPER can generate such an index, and TBLOOK can scale
the ramping index right by up to 16 bits, so it need not do anything fancy
to take a left adjusted ramp.
-------------------------------------- Mod0
ADR: 00000000000011010000 IN (6.5)
↑(binary point)
*
11111100000000000000[0000000000 M0 (-2↑-5) shift out fraction,
and invert sign.
+ RM(0)*M1(0)
↓
-------------------------------------- Mod1
TMP: 11111111111111111010 IN (-6)
*
00000000000000100000[0000000000 M0 (2↑5) integer
+
ADR: 00000000000011010000 RM (6.5) (See note below)
* ↑(binary point)
00000000000000000001[0000000000 M1 (1) integer
↓
FRAC: 00000000000000010000 (.5)
Note: since Mod1 must reference both FRAC and ADR, and since ADR
is from last pass, Mod1 must get ADR on the same pass Mod0 gets it.
This means that Mod1 must be far enough down the pipe of this pass to get
FRAC as a valid input. Pete says it should therefore be 2*Mod0+7.
To do the interpolation is less hairy. We take XN and XNP1
and FRAC and do the following:
Mod2 and Mod3 are in FOUR_QUAD_MULTIPLY mode, Mod4 is in MIXING.
Xz← m*X[n+1]*1/w + m*X[n]*(-1/w) + X[n].
Mod2: FRAC IN Mod3: XN IN Mod4: XN IN
* * *
XNP1 RM FRAC RM 1 M0
* * +
M0 (1/2↑5) M0 (1/2↑5) 0*zero M1*RM
↓ ↓ ↓
XZ XZ XZ
There, now wasn't that fun?
;